<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script>
        // 为什么要有async/await存在?是因为要解决大量复杂不易读的Promise异步问题
        // async声明的函数的返回本质上是一个Promise
        // 只要声明了这个函数是async，那么内部不管你怎么处理，它的返回肯定是个Promise
        // const a = (async function () {
        //     return '我是Promise'
        // })()
        // console.log(a)
        // // 返回的是一个Promise
        // // Promise {<resolved>: "我是Promise"}

        // // 等同于:
        // const b = (async function () {
        //     return Promise.resolve('我是Promise')
        // })()
        // console.log(b)

        // const demo = (async function () {
        //     return Promise.resolve('我是Promise')
        //     // 等同于 
        //     //return '我是Promise'
        //     // 等同于
        //     // return new Promise((resolve, reject) => {
        //     //     resolve('我是Promise')
        //     // })
        // })()
        // demo.then(result => {
        //     console.log(result) //这里拿到返回值
        // })

        // // await的本质是可以提供等同于'同步效果'的等待异步返回能力的语法糖
        // // 用await声明的Promise异步返回，必须“等待”到有返回值的时候，代码才继续执行下去
        // // 请记住await是在等待一个Promise的异步返回
        // const demo1 = (async () => {
        //     let result = await new Promise((resolve, reject) => {
        //         setTimeout(() => {
        //             resolve('我延迟了一秒')
        //         }, 1000)
        //     })
        //     console.log('我由于上面的程序还没执行完，先不执行，等待一会')
        //     return result
        // })()
        // // demo1的返回当做Promise
        // demo1.then(result => {
        //     console.log('输出', result)
        // })

        // 输出结果
        // 我由于上面的程序还没执行完，先不执行，等待一会
        // 输出 我延迟了一秒

        // 这里需要注意一点:then的执行总是最后的


        // 推荐的写法是带上then,更规范
        // 当然没有返回也是没问题的，demo会照常执行，以下写法是不带返回值的写法
        // const demo2 = async () => {
        //     let result2 = await new Promise((resolve, reject) => {
        //         setTimeout(() => {
        //             resolve('我延迟了一秒')
        //         }, 1000)
        //     })
        //     console.log('我由于上面的程序还没执行完，先不执行，等待一会')
        // }
        // demo2()
        // 输出结果
        // 我由于上面的程序还没执行完，先不执行，等待一会

        // 重点！！请记住，await是在等待一个Promise的异步返回

        // await也可以用于声明一般情况下的传值
        // const demo3 = (async () => {
        //     let message = '我是声明值'
        //     let result = await message
        //     console.log(result)
        //     console.log('我由于上面的程序还没执行完，先不执行，等待一会')
        //     return result
        // })()
        // demo3.then(resulttt => {
        //     console.log('输出', resulttt)
        // })

        // 输出结果
        // 我是声明值
        // 我由于上面的程序还没执行完，先不执行，等待一会
        // 输出 我是声明值

        // 这里需要注意一点:then的执行总是最后的

        // 3.4 async/await优势实战
        const setDelay = (millisecond) => {
            return new Promise((resolve, reject) => {
                if (typeof millisecond != 'number') {
                    reject(new Error('参数必须是number类型'))
                }
                setTimeout(() => {
                    resolve(`我延迟了${millisecond}毫秒后输出的`)
                }, millisecond)
            })
        }

        const setDelaySecond = (seconds) => {
            return new Promise((resolve, reject) => {
                if (typeof seconds != 'number' || seconds > 10) {
                    reject(new Error('参数必须是number类型，并且小于等于10'))
                }
                setTimeout(() => {
                    resolve(`我延迟了${seconds}秒后输出的，注意单位是秒`)
                }, seconds * 1000)
            })
        }
        // 以上是两个延时函数，现在想实现的需求是:先延时1秒，再延迟2秒，再延时1秒，最后输出'完成'
        // 这个过程如果用then的写法，大概如下:
        // setDelay(1000).then(result => {
        //     console.log(result)
        //     return setDelaySecond(2)
        // }).then(result => {
        //     console.log(result)
        //     return setDelay(1000)
        // }).then(result => {
        //     console.log(result)
        //     console.log('完成')
        // }).catch(err => {
        //     console.log(err)
        // })

        // 可以看出，用.then写法太繁琐，现在我们来试试async/await
        // (async () => {
        //     const result1 = await setDelay(1000)
        //     console.log(result1)
        //     const result2 = await setDelaySecond(2)
        //     console.log(result2)
        //     const result3 = await setDelay(1000)
        //     console.log(result3)
        //     console.log('完成了')
        // })()

        // 输出结果
        // 我延迟了1000毫秒后输出的
        // 我延迟了2秒后输出的，注意单位是秒
        // 我延迟了1000毫秒后输出的
        // 完成了

        // 3.5 async/await错误处理
        // 因为async函数返回的是一个promise，所以我们可以在外面catch住错误

        // const demo4 = (async () => {
        //     const result1 = await setDelay(1000)
        //     console.log(result1)
        //     const result2 = await setDelaySecond(2)
        //     console.log(result2)
        //     const result3 = await setDelay(1000)
        //     console.log(result3)
        //     console.log('完成了')
        // })()

        // demo4.catch(err => {
        //     console.log(err)
        // })

        // 输出结果
        // 我延迟了1000毫秒后输出的
        // 我延迟了2秒后输出的，注意单位是秒
        // 我延迟了1000毫秒后输出的
        // 完成了

        // 在async函数的catch中捕获错误，当做一个Promise处理。也可以用try...catch语句，就不用在外面cacth了

        // (async () => {
        //     try {
        //         const result1 = await setDelay(1000)
        //         console.log(result1)
        //         const result2 = await setDelaySecond(2)
        //         console.log(result2)
        //         const result3 = await setDelay(1000)
        //         console.log(result3)
        //         console.log('完成了')
        //     } catch (e) {
        //         console.log(e)//这里捕获错误
        //     }
        // })()

        // 输出结果
        // 我延迟了1000毫秒后输出的
        // 我延迟了2秒后输出的，注意单位是秒
        // 我延迟了1000毫秒后输出的
        // 完成了

        // 3.6 async/await的中断（终止程序）
        // let count = 6
        // const demo5 = (async () => {
        //     const result = await setDelay(1000)
        //     console.log(result)
        //     const result1 = await setDelaySecond(count)
        //     console.log(result1)
        //     if (count > 5) {
        //         return '我退出了，下面的不进行了'
        //         // return 
        //         // return false //这些写法都可以
        //         // return null
        //     }
        //     console.log(await setDelay(1000))
        //     console.log('完成了')
        // })()
        // demo5.then(result => {
        //     console.log(result)
        // })
        //     .catch(err => {
        //         console.log(err)
        //     })

        // 输出结果:
        // 我延迟了1000毫秒后输出的
        // 我延迟了6秒后输出的，注意单位是秒
        // 我退出了，下面的不进行了

        // 实际就是直接return反悔了一个Promise,相当于return Promise.resolve('我退出了，下面的不进行了')
        // 也可以返回一个‘拒绝’:return Promise.reject(new Error('拒绝'))

        // 总结:async函数实质就是返回一个Promise!!!

        // ------------------------学习笔记二-------------------------------
        // 1.1 基础概念
        // async 用来表示函数是异步的，定义的函数会返回一个promise对象，可以使用then方法添加回调函数
        // async function demo01() {
        //     return 123
        // }
        // demo01().then(val => {
        //     console.log(val)//123
        // })
        // 若async定义的函数有返回值,return 123;相当于Promise.resolve(123),没有声明式的return则相当于执行了Promise.resolve(123)

        // function sleep(second) {
        //     return new Promise((resolve, reject) => {
        //         setTimeout(() => {
        //             resolve('enough sleep')
        //         }, second)
        //     })
        // }
        // function normalFunc() {
        //     console.log('normalFunc')
        // }
        // async function awaitDemo() {
        //     await normalFunc()
        //     console.log('something,~~')
        //     let result = await sleep(2000)
        //     console.log(result)// 两秒之后会被打印出来
        // }
        // awaitDemo()

        // 输出结果
        // normalFunc
        // something,~~
        // enough sleep

        // await后面可以跟任何的js表达式,虽然说await可以等很多类型的东西，但是它最主要的意图是用来等待Promise对象的状态被resolved
        // 如果await的是promise对象会造成异步函数停止执行并且等待promise的解决,如果等的是正常的表达式则立即执行

        // 1.2 实例说明
        // function sleep2(second, param) {
        //     return new Promise((resolve, reject) => {
        //         setTimeout(() => {
        //             resolve(param)
        //         }, second)
        //     })
        // }
        // async function test() {
        //     let result1 = await sleep2(2000, 'req01')
        //     let result2 = await sleep2(1000, 'req02' + result1)
        //     let result3 = await sleep2(500, 'req03' + result2)
        //     console.log(result1)
        //     console.log(result2)
        //     console.log(result3)
        // }
        // test()
        // 打印结果
        // req01
        // req02req01
        // req03req02req01

        // 1.3 错误处理
        // 上述的代码给的都是resolve的情况，那么reject的时候该如何处理?
        // function sleep3(second) {
        //     return new Promise((resolve, reject) => {
        //         setTimeout(() => {
        //             reject('want to sleep')
        //         }, second)
        //     })
        // }
        // async function errorDemoSuper() {
        //     try {
        //         let result = await sleep3(3000)
        //         console.log(result)
        //     } catch (err) {
        //         console.log(err)
        //     }
        // }
        // errorDemoSuper() // want to sleep
        // 有了 try catch 之后我们就能够拿到 Promise.reject 回来的数据了

        // 1.4 小心你的并行处理（重要！！！可用在echart多个表格同时异步请求）
        // 我有三个异步请求需要发送，相互没有关联，只是需要当请求都结束后将界面的loading清除掉即可
        function sleep4(second) {
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    resolve('request done! ' + Math.random());
                }, second);
            })
        }

        async function correctDemo() {
            let p1 = sleep4(1000);
            let p2 = sleep4(1000);
            let p3 = sleep4(1000);
            await Promise.all([p1, p2, p3]);
            console.log('clear the loading~');
        }
        correctDemo();// clear the loading~
    </script>
</head>

<body>

</body>

</html>